package com.niiwoo.civet.trade.service.local.databackflow;

import com.niiwoo.civet.trade.dao.entity.DataBackflowDetails;
import com.niiwoo.civet.trade.dao.entity.DataBackflowStatus;
import com.niiwoo.civet.trade.dao.mapper.DataBackflowDetailsMapperExt;
import com.niiwoo.civet.trade.dao.mapper.DataBackflowStatusMapperExt;
import com.niiwoo.civet.trade.dto.DataBackflowStatusAndDetailsDTO;
import com.niiwoo.civet.trade.enums.DataBackflowStatusDataStatusEnum;
import com.niiwoo.civet.trade.enums.DataBackflowStatusDataTypeEnum;
import com.niiwoo.civet.trade.enums.ProjectTypeEnum;
import com.niiwoo.tripod.base.utils.DateUtils;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;

/**
 * @author wping
 * @Description: 数据回流状态服务类
 * @date 2018/4/16 9:35
 */
@Slf4j
@Service
public class DataBackflowStatusService {

    @Autowired
    private DataBackflowStatusMapperExt dataBackflowStatusMapperExt;

    @Autowired
    private DataBackflowDetailsMapperExt dataBackflowDetailsMapperExt;

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;

    /**
     * 更新数据回流状态信息表
     *
     * @param isBackflowSuccess      天秤回流是否成功
     * @param dataBackflowStatus     数据回流状态DTO
     * @param backflowTimeoutSeconds 超时时间（单位秒），超时设定时间回流失败
     * @param executeTimesThreshold  执行次数阈值，超过执行次数回流失败
     * @param desc                   描述(成功、失败原因)
     * @return 成功返回true, 否则false
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean updateDataBackflowStatus(boolean isBackflowSuccess, DataBackflowStatus dataBackflowStatus, int backflowTimeoutSeconds, int executeTimesThreshold, String desc) {

        if (dataBackflowStatus == null) {
            return false;
        }
        String methodName = "更新借款流程数据回流状态表, userId:" + dataBackflowStatus.getUserId() + ", projectId:" + dataBackflowStatus.getProjectId() + ", projectType:" + dataBackflowStatus.getProjectType() + ", dataType:" + dataBackflowStatus.getDataType();

        Date now = new Date();
        if (isBackflowSuccess) {
            dataBackflowStatus.setDataStatus(DataBackflowStatusDataStatusEnum.BACKFLOW_SUCCESSED.getStatus().byteValue());
            if (StringUtils.isEmpty(desc)) {
                desc = DataBackflowStatusDataStatusEnum.BACKFLOW_SUCCESSED.getDesc();
            }
        } else {
            DataBackflowStatusDataStatusEnum dataStatusEnum = DataBackflowStatusDataStatusEnum.FAILED_WITH_RETRY;
            // 回流次数超过设置执行次数
            if (dataBackflowStatus.getExecuteTimes() != null && dataBackflowStatus.getExecuteTimes() >= executeTimesThreshold) {
                dataStatusEnum = DataBackflowStatusDataStatusEnum.FAILED;
                desc = desc + "-失败, 执行次数超过:" + executeTimesThreshold;
            }

            // 回流用时超过设置时间
            if (dataBackflowStatus.getFirstBackflowTime() != null && !DateUtils.isBeforeNow(dataBackflowStatus.getFirstBackflowTime(), backflowTimeoutSeconds)) {
                dataStatusEnum = DataBackflowStatusDataStatusEnum.FAILED;
                desc = desc + "-失败, 执行时间超过:" + backflowTimeoutSeconds;
            }
            dataBackflowStatus.setDataStatus(dataStatusEnum.getStatus().byteValue());
        }
        dataBackflowStatus.setDesc(subString(desc, 256));

        dataBackflowStatus.setExecuteTimes((dataBackflowStatus.getExecuteTimes() == null ? 1 : dataBackflowStatus.getExecuteTimes()) + 1);
        if (dataBackflowStatus.getFirstBackflowTime() == null) {
            dataBackflowStatus.setFirstBackflowTime(now);
        }
        dataBackflowStatus.setLatelyBackflowTime(now);
        dataBackflowStatus.setUpdateTime(now);
        int count = dataBackflowStatusMapperExt.updateByPrimaryKeySelective(dataBackflowStatus);
        log.info(methodName + "-更新条数:{}", count);

        return true;
    }

    private String subString(String value, int maxLength) {
        if (StringUtils.isNotEmpty(value)) {
            if (value.length() > maxLength) {
                return value.substring(0, maxLength);
            } else {
                return value;
            }
        }
        return null;
    }

    /**
     * 批量初始化未回流的回流数据
     *
     * @param dataBackflowStatusAndDetailsDTOs
     */
    @Transactional(rollbackFor = Exception.class)
    public void initDataBackflowStatus(List<DataBackflowStatusAndDetailsDTO> dataBackflowStatusAndDetailsDTOs) {
        if (!CollectionUtils.isEmpty(dataBackflowStatusAndDetailsDTOs)) {
            for (DataBackflowStatusAndDetailsDTO dto : dataBackflowStatusAndDetailsDTOs) {
                initDataBackflowStatus(dto.getUserId(), dto.getProjectId(), dto.getProjectTypeEnum(), dto.getDataTypeEnum(), dto.getContentDetails());
            }
        }
    }

    /**
     * 初始化未回流的回流数据
     *
     * @param userId          用户ID(必传)
     * @param projectId       标的ID(发布借款时必传)
     * @param projectTypeEnum 产品类型 参考ProjectTypeEnum
     * @param dataTypeEnum    回流类型(必传)
     * @param contentDetails  回流信息(json报文, 有就传)
     * @return 插入成功条数
     */
    @Transactional(rollbackFor = Exception.class)
    public Long initDataBackflowStatus(String userId, Long projectId, ProjectTypeEnum projectTypeEnum, DataBackflowStatusDataTypeEnum dataTypeEnum, String contentDetails) {
        return insertDataBackflowStatusAndDetails(userId, projectId, projectTypeEnum, dataTypeEnum, DataBackflowStatusDataStatusEnum.WAITING_BACKFLOW, null, null, contentDetails, 0);
    }

    /**
     * 插入数据回流状态信息表、回流详情数据表
     *
     * @param userId             用户ID(必传)
     * @param projectId          标的ID(发布借款时必传)
     * @param projectTypeEnum    产品类型 参考ProjectTypeEnum
     * @param dataTypeEnum       回流类型(必传)
     * @param dataStatusEnum     回流状态
     * @param firstBackflowTime  首次回流时间（用于计算回流超时）
     * @param latelyBackflowTime 最近回流时间(成功、失败)
     * @param contentDetails     回流信息(json报文, 有就传)
     * @param executeTimes       回流次数
     * @return 返回数据回流状态信息表主键ID
     */
    private Long insertDataBackflowStatusAndDetails(String userId, Long projectId, ProjectTypeEnum projectTypeEnum, DataBackflowStatusDataTypeEnum dataTypeEnum, DataBackflowStatusDataStatusEnum dataStatusEnum, Date firstBackflowTime, Date latelyBackflowTime, String contentDetails, Integer executeTimes) {

        String methodName = "插入借款流程数据回流状态表, userId:" + userId + ", projectId:" + projectId + ", productType:" + (projectTypeEnum != null ? projectTypeEnum.getValue() : null) + ", dataType:" + (dataTypeEnum != null ? dataTypeEnum.getType() : null);
        if (StringUtils.isEmpty(userId) || dataTypeEnum == null) {
            log.error(methodName + "-失败，userId/dataType必须非空");
            throw new RuntimeException("userId/dataType必须非空");
        }

        if (projectId == null) {
            if (DataBackflowService.BLOCK_EXECUTE_BACKFLOW.contains(dataTypeEnum.getType().byteValue())) {
                log.error(methodName + "-失败，projectId必须非空");
                throw new RuntimeException("projectId必须非空");
            }
        }

        if (StringUtils.isEmpty(contentDetails)) {
            if (DataBackflowStatusDataTypeEnum.ADDRESS_LIST.getType() == dataTypeEnum.getType().byteValue()) {
                log.error(methodName + "-失败，通讯录详情必须非空");
                throw new RuntimeException("通讯录详情必须非空");
            }
        }

        Date now = new Date();
        Long detailsId = null;
        if (StringUtils.isNotEmpty(contentDetails)) {
            DataBackflowDetails dataBackflowDetails = new DataBackflowDetails();
            detailsId = snowflakeIdWorker.nextId();
            dataBackflowDetails.setId(detailsId);
            String detailsBase64 = null;
            try {
                detailsBase64 = Base64.encodeBase64URLSafeString(contentDetails.getBytes("UTF-8"));
            } catch (Exception e) {
                log.error(methodName + "-base64加密失败", e);
                throw new RuntimeException(e);
            }
            dataBackflowDetails.setContents(detailsBase64);
            dataBackflowDetails.setCreateTime(now);
            dataBackflowDetails.setUpdateTime(now);
            dataBackflowDetailsMapperExt.insertSelective(dataBackflowDetails);
        }

        DataBackflowStatus dataBackflowStatus = new DataBackflowStatus();
        dataBackflowStatus.setId(snowflakeIdWorker.nextId());
        dataBackflowStatus.setUserId(userId);
        dataBackflowStatus.setProjectId(projectId);
        dataBackflowStatus.setProjectType(projectTypeEnum != null ? projectTypeEnum.getValue() : null);
        dataBackflowStatus.setDataType(dataTypeEnum != null ? dataTypeEnum.getType() : null);
        dataBackflowStatus.setDataStatus(dataStatusEnum != null ? dataStatusEnum.getStatus() : null);
        dataBackflowStatus.setDesc(dataStatusEnum != null ? dataStatusEnum.getDesc() : null);
        dataBackflowStatus.setLatelyBackflowTime(latelyBackflowTime);
        dataBackflowStatus.setDetailsId(detailsId);
        dataBackflowStatus.setExecuteTimes(executeTimes);
        dataBackflowStatus.setCreateTime(now);
        dataBackflowStatus.setUpdateTime(now);

        int count = dataBackflowStatusMapperExt.insertSelective(dataBackflowStatus);
        log.info(methodName + "-插入条数:{}", count);

        return dataBackflowStatus.getId();

    }


}
